package com.lion.common.spring.security;

import com.chris.dev.base.libs.v1.http.protocols.HttpResult;
import com.lion.common.base.exceptions.CommonException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;

import java.nio.charset.StandardCharsets;

/**
 * @author Chris Chan
 * Create On 2025/8/6 下午10:19
 * Use for: 通用安全配置
 * Explain:
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class CommonSecurityConfig implements SecurityWhiteList {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 1. 禁用所有默认认证方式
                .httpBasic(AbstractHttpConfigurer::disable)
                .formLogin(AbstractHttpConfigurer::disable)
                .logout(AbstractHttpConfigurer::disable)
                .anonymous(AbstractHttpConfigurer::disable)

                // 2. 禁用CSRF和CORS（API网关通常需要）
                .csrf(AbstractHttpConfigurer::disable)
                .cors(AbstractHttpConfigurer::disable)

                // 3. 配置白名单
                .authorizeHttpRequests(authorize -> authorize
                        //白名单由网关控制
                        .requestMatchers(WEB_WHITELIST).permitAll()
                        .requestMatchers(AUTH_WHITELIST).permitAll()
                        .anyRequest().authenticated()
                )
                // 4.异常处理
                .exceptionHandling(exceptions -> exceptions
                        .authenticationEntryPoint(unauthorizedHandler()) // 未认证处理
                        .accessDeniedHandler(forbiddenHandler()) // 权限不足处理
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                        .authenticationEntryPoint(new CustomBearerTokenAuthenticationEntryPoint())
                        .jwt(jwt -> jwt
                                .jwtAuthenticationConverter(new CustomJwtAuthenticationConverter())
                        )
                );

        return http.build();
    }

    /**
     * 配置静态资源白名单
     * @return
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web
                .ignoring()
                // 解决前端一个有关跨域的重要报错
                .requestMatchers(HttpMethod.OPTIONS, "/**")
                .requestMatchers(WEB_WHITELIST);
    }


    // 401 未认证处理
    private AuthenticationEntryPoint unauthorizedHandler() {
        // 不知道为啥，抛异常不起作用
        return (request, response, ex) -> {
            // 设置响应状态和内容类型
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());

            // 创建响应体
            String body = HttpResult.fail(401, "无效或过期的Token").toJson();
            // 写入响应
            response.getWriter().write(body);
            response.getWriter().flush();
        };
    }

    // 403 权限不足处理
    private AccessDeniedHandler forbiddenHandler() {
        return (request, response, ex) -> {
            throw CommonException.of(403, "权限不足");
        };
    }
}
